#pragma once

#include <CParticle.h>
#include <CVector.h>
#include <CUtil.h>
#include <Container.h>
#include <C3DField.h>

/*
 * Used for sorting particles, like on distance etc. Not used in MyBody 
 */

// internal sorting (not needed here.. but if we need it)
typedef struct particle_sort {
 bool operator() (const CParticle& lhs, const CParticle& rhs) const {
    return lhs.dist>rhs.dist;
 }        
};


// Particle Save structure: Keep only P and V!
typedef struct particle_save {
  CVector P, V;
  unsigned int halo;
};


// Gadget 2.0 data file header
typedef struct io_header_1
{
    int      npart[6];
    double   mass[6];//10^10 Msun/h
    double   time;
    double   redshift;
    int      flag_sfr;
    int      flag_feedback;
    int      npartTotal[6];
    int      flag_cooling;
    int      num_files;
    double   BoxSize;//kpc/h
    double   Omega0;
    double   OmegaLambda;
    double   HubbleParam;
    char     fill[256- 6*4- 6*8- 2*8- 2*4- 6*4- 2*4 - 4*8];  /* fills to 256 Bytes */
};


/*
 * The CParticles class
 * Virtual parent class for all energy content types. Must implement various methods such
 * as calculating the density field rho etc
 *   Links to parameters and cosmology
 *   Initial positions
 *   Virtual methods
 *   Density fields / FFT / Derivatives
 *   Load and Save particle data
 *
 */

class CParticles : public Container<CParticle> {
 public:

  // Root node for treecode
  int Type;
  // Link to cosmological and io parameters 

  // Only initial stuff, disregard. Color of particles, etc
  CVector pos, pos_spread, color, color_spread;

  /* The 3D Fields: 
   *   Rho - matter density
   *   RhoF - matter density fourier transformed
   *   Fx,Fy,Fz : Nabla Rho in real space
   *   *SmoothField : Pointer to gaussian smoothing field
   */
  C3DField Rho, RhoF, Fx, Fy, Fz, *SmoothField;


  // Rendering properties
  double totalmass, boundsize;
  bool render_acc;
  CVector center;

  // dots contain all point positions to be rendered as billboards

  
  // MaxVelocity is the largest particle velocity. Used for time scaling. 
  double MaxVelocity;

  enum {
    start_normal=0,
    start_point=1
  };
  

  // All child classes must implement calculating the field Rho
  virtual void CalculateRho() = 0;
  // All child classes must implement force calculations
  virtual void Gravity_Field(C3DField& Fx, C3DField& Fy, C3DField& Fz) = 0;

  void FindMaxVelocity();
  // These will have to be changed: here for a while. Not usable right now!
  void Gravity_1(double time);
  void Gravity_n2(double time);
  void ApplyField(CParticles* F, int);

  // Applies the treecode
  void ApplyTree();
  // Calculates a boundary box: Currently not used, empty
  void BoundaryBox(double size, double time, double str);
  // Refines the tree
  void Refine();
  // Applies the damping force due to universe expansion (-V*(..))
  void ApplyExpansion();
  // Initialized particles from a field
  void InitializeFromField(C3DField& Field);
  
  // Initialize and allocate particles
  void Init(int pno, CVector ppos, CVector ppos_spread,  CVector pcolor, CVector pcolor_spread, double BoxSize, int GridSize, double dmin, C3DField* SF);
  void InitializePhysics();
 
  // Move particles and set A to 0
  void Move(double time);


  // IO functions: load and save
  void SaveText(string Filename);
  void LoadText(string Filename);

  void SaveBin(string Filename);
  void LoadBin(string Filename);

  void LoadGadget(string Filename);

  void LoadMLAPASCII(string Filename);
  int FileSize(const char* sFileName);


 private:  
  // void init_particle(CParticle* p);
  CParticle InitializeObject();
  void Sort();

};
